/*
 *
 *  Copyright (C) 2012-2024
 *  All rights reserved, Designed By 杭州连线客信息技术有限公司
 *  注意：
 *  本软件为杭州连线客信息技术有限公司开发研制，未经购买不得使用
 *  购买后可获得全部源代码（禁止转卖、分享、上传到码云、github等开源平台）
 *  一经发现盗用、分享等行为，将追究法律责任，后果自负
 *
 */

package com.lxk.mall.pms.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lxk.mall.pms.controller.app.vo.AppProductSpuPageReqVO;
import com.lxk.mall.pms.controller.app.vo.ProductCategoryListReqVO;
import com.lxk.mall.pms.domain.PmsProductCategory;
import com.lxk.mall.pms.domain.PmsProductSpu;
import com.lxk.mall.pms.domain.bo.spu.*;
import com.lxk.mall.pms.domain.vo.spu.PmsProductSpuVo;
import com.lxk.mall.pms.enums.PmsErrorCodeConstants;
import com.lxk.mall.pms.enums.ProductConstants;
import com.lxk.mall.pms.enums.ProductSpuStatusEnum;
import com.lxk.mall.pms.mapper.PmsProductSpuMapper;
import com.lxk.mall.pms.service.IPmsProductBrandService;
import com.lxk.mall.pms.service.IPmsProductCategoryService;
import com.lxk.mall.pms.service.IPmsProductSkuService;
import com.lxk.mall.pms.service.IPmsProductSpuService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.enums.CommonStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.CollectionUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.*;

import static com.lxk.mall.pms.enums.PmsErrorCodeConstants.SPU_SAME_SPU_CODE;
import static org.dromara.common.core.utils.CollectionUtils.convertList;
import static org.dromara.common.core.utils.CollectionUtils.convertMap;

/**
 * 商品spuService业务层处理
 *
 * @author Lion Li
 * @date 2024-06-06
 */
@RequiredArgsConstructor
@Service
public class PmsProductSpuServiceImpl implements IPmsProductSpuService {

    private final PmsProductSpuMapper baseMapper;

    private final IPmsProductCategoryService categoryService;

    @Resource
    @Lazy // 循环依赖，避免报错
    private IPmsProductSkuService productSkuService;

    @Resource
    private IPmsProductBrandService brandService;

    //定义事务模板对象
    private final TransactionTemplate transactionTemplate;

    /**
     * 查询商品spu
     *
     * @param id 主键
     * @return 商品spu
     */
    @Override
    public PmsProductSpu queryById(Long id) {
        return baseMapper.selectById(id);
    }

    /**
     * 分页查询商品spu列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 商品spu分页列表
     */
    @Override
    public TableDataInfo<PmsProductSpuVo> queryPageList(ProductSpuPageReqBO bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PmsProductSpu> lqw = buildQueryWrapper(bo);
        Page<PmsProductSpuVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的商品spu列表
     *
     * @param bo 查询条件
     * @return 商品spu列表
     */
    @Override
    public List<PmsProductSpuVo> queryList(ProductSpuPageReqBO bo) {
        LambdaQueryWrapper<PmsProductSpu> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 查询IdList
     */
    @Override
    public List<PmsProductSpuVo> queryByIdList(List<Long> idList) {
        if (CollUtil.isEmpty(idList)) {
            return CollUtil.newArrayList();
        }
        LambdaQueryWrapper<PmsProductSpu> lqw = Wrappers.lambdaQuery();
        lqw.in(PmsProductSpu::getId, idList);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PmsProductSpu> buildQueryWrapper(ProductSpuPageReqBO bo) {
        LambdaQueryWrapper<PmsProductSpu> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getName()), PmsProductSpu::getName, bo.getName());
        lqw.eq(bo.getCategoryId() != null, PmsProductSpu::getCategoryId, bo.getCategoryId());
        lqw.eq(bo.getBrandId() != null, PmsProductSpu::getBrandId, bo.getBrandId());
        lqw.eq(bo.getBrandId() != null, PmsProductSpu::getBrandId, bo.getBrandId());
        lqw.eq(bo.getProductType() != null, PmsProductSpu::getProductType, bo.getProductType());
        appendTabQuery(bo.getTabType(), lqw);
        return lqw;
    }

    /**
     * 新增商品spu
     *
     * @param bo 商品spu
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(PmsProductSpuBo bo) {
        PmsProductSpu add = MapstructUtils.convert(bo, PmsProductSpu.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改商品spu
     *
     * @param bo 商品spu
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(PmsProductSpuBo bo) {
        PmsProductSpu update = MapstructUtils.convert(bo, PmsProductSpu.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PmsProductSpu entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除商品spu信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public Map<Integer, Long> getTabsCount(String productType) {
        Map<Integer, Long> counts = new HashMap<>(5);
        // 查询销售中的商品数量
        counts.put(ProductSpuPageReqBO.FOR_SALE, baseMapper.selectCount(
            new LambdaQueryWrapper<PmsProductSpu>()
                .eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.ENABLE.getStatus())
                .eq(StrUtil.isNotBlank(productType), PmsProductSpu::getProductType, productType))
        );
        // 查询仓库中的商品数量
        counts.put(ProductSpuPageReqBO.IN_WAREHOUSE, baseMapper.selectCount(
            new LambdaQueryWrapper<PmsProductSpu>()
                .eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.DISABLE.getStatus())
                .eq(StrUtil.isNotBlank(productType), PmsProductSpu::getProductType, productType))
        );
        // 查询售空的商品数量
        counts.put(ProductSpuPageReqBO.SOLD_OUT,
            baseMapper.selectCount(new LambdaQueryWrapper<PmsProductSpu>()
                .eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.ENABLE.getStatus())
                .eq(StrUtil.isNotBlank(productType), PmsProductSpu::getProductType, productType)
                .eq(PmsProductSpu::getStock, 0)));
        // 查询触发警戒库存的商品数量
        counts.put(ProductSpuPageReqBO.ALERT_STOCK,
            baseMapper.selectCount(productType));
        // 查询回收站中的商品数量
        counts.put(ProductSpuPageReqBO.RECYCLE_BIN,
            baseMapper.selectCount(new LambdaQueryWrapper<PmsProductSpu>()
                .eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus())
                .eq(StrUtil.isNotBlank(productType), PmsProductSpu::getProductType, productType))
        );
        return counts;
    }

    @Override
    public List<PmsProductSpu> getSpuListByStatus(Integer status) {
        return baseMapper.selectList(new LambdaQueryWrapper<PmsProductSpu>().eq(PmsProductSpu::getStatus, status).orderByDesc(PmsProductSpu::getSort));
    }

    @Override
    public List<PmsProductSpu> getSpuList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        Map<Long, PmsProductSpu> spuMap = convertMap(baseMapper.selectBatchIds(ids), PmsProductSpu::getId);
        // 需要按照 ids 顺序返回。例如说：店铺装修选择了 [3, 1, 2] 三个商品，返回结果还是 [3, 1, 2]  这样的顺序
        return convertList(ids, spuMap::get);
    }

    @Override
    public TableDataInfo<PmsProductSpu> getSpuPage(AppProductSpuPageReqVO pageReqVO) {
        // 查找时，如果查找某个分类编号，则包含它的子分类。因为顶级分类不包含商品
        Set<Long> categoryIds = new HashSet<>();
        if (pageReqVO.getCategoryId() != null && pageReqVO.getCategoryId() > 0) {
            categoryIds.add(pageReqVO.getCategoryId());
            ProductCategoryListReqVO reqVO = new ProductCategoryListReqVO();
            reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
            reqVO.setParentId(pageReqVO.getCategoryId());
            List<PmsProductCategory> categoryChildren = categoryService.getCategoryList(reqVO);
            categoryIds.addAll(convertList(categoryChildren, PmsProductCategory::getId));
        }
        if (CollUtil.isNotEmpty(pageReqVO.getCategoryIds())) {
            categoryIds.addAll(pageReqVO.getCategoryIds());
            ProductCategoryListReqVO reqVO = new ProductCategoryListReqVO();
            reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
            reqVO.setParentIds(pageReqVO.getCategoryIds());
            List<PmsProductCategory> categoryChildren = categoryService.getCategoryList(reqVO);
            categoryIds.addAll(convertList(categoryChildren, PmsProductCategory::getId));
        }
        // 分页查询
        return TableDataInfo.build(baseMapper.selectPage(pageReqVO, categoryIds));
    }

    @Override
    public void updateBrowseCount(Long id, int incrCount) {
        baseMapper.updateBrowseCount(id, incrCount);
    }

    @Override
    public Long getSpuCountByCategoryId(Long categoryId) {
        LambdaQueryWrapper<PmsProductSpu> lqw = Wrappers.lambdaQuery();
        lqw.eq(PmsProductSpu::getCategoryId, categoryId);
        return baseMapper.selectCount(lqw);
    }

    @Override
    public PmsProductSpu getSpu(Long spuId) {
        return baseMapper.selectById(spuId);
    }

    @Override
    public Long createSpu(ProductSpuSaveReqBO createReqVO) {
        // 校验分类、品牌
        validateCategory(createReqVO.getCategoryId());
        brandService.validateProductBrand(createReqVO.getBrandId());
        // 校验 SKU
        List<ProductSkuSaveReqBO> skuSaveReqList = createReqVO.getSkus();
        productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());

        if (StrUtil.isNotBlank(createReqVO.getSpuCode())) {
            Long count = baseMapper.selectCount(new LambdaQueryWrapper<PmsProductSpu>().eq(PmsProductSpu::getSpuCode, createReqVO.getSpuCode()));
            if (count > 0) {
                throw new ServiceException(SPU_SAME_SPU_CODE);
            }
        }

        PmsProductSpu spu = MapstructUtils.convert(createReqVO, PmsProductSpu.class);
        // 初始化 SPU 中 SKU 相关属性
        initSpuFromSkus(spu, skuSaveReqList);
        transactionTemplate.execute(status -> {
            // 插入 SPU
            baseMapper.insert(spu);
            // 插入 SKU
            productSkuService.createSkuList(spu.getId(), skuSaveReqList);
            return Boolean.TRUE;
        });
        // 返回
        return spu.getId();
    }

    @Override
    public void updateSpu(ProductSpuSaveReqBO updateReqVO) {
        // 校验 SPU 是否存在
        validateSpuExists(updateReqVO.getId());
        // 校验分类、品牌
        validateCategory(updateReqVO.getCategoryId());
        brandService.validateProductBrand(updateReqVO.getBrandId());
        // 校验SKU
        List<ProductSkuSaveReqBO> skuSaveReqList = updateReqVO.getSkus();
        productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType());

        if (StrUtil.isNotBlank(updateReqVO.getSpuCode())) {
            Long count = baseMapper.selectCount(new LambdaQueryWrapper<PmsProductSpu>()
                .eq(PmsProductSpu::getSpuCode, updateReqVO.getSpuCode()).ne(PmsProductSpu::getId, updateReqVO.getId()));
            if (count > 0) {
                throw new ServiceException(SPU_SAME_SPU_CODE);
            }
        }

        // 更新 SPU
        PmsProductSpu updateObj = MapstructUtils.convert(updateReqVO, PmsProductSpu.class);
        initSpuFromSkus(updateObj, skuSaveReqList);
        baseMapper.updateById(updateObj);
        // 批量更新 SKU
        productSkuService.updateSkuList(updateObj.getId(), updateReqVO.getSkus());
    }

    @Override
    public void updateSpuStock(Map<Long, Integer> stockIncrCounts) {
        stockIncrCounts.forEach(baseMapper::updateStock);
    }

    @Override
    public void updateSpuStatus(ProductSpuUpdateStatusReqBO updateReqVO) {
// 校验存在
        validateSpuExists(updateReqVO.getId());
        // TODO ：【可选】参与活动中的商品，不允许下架？？？
        // 更新状态
        PmsProductSpu pmsProductSpu = baseMapper.selectById(updateReqVO.getId());
        pmsProductSpu.setStatus(updateReqVO.getStatus());
        baseMapper.updateById(pmsProductSpu);
    }

    @Override
    public void appendTabQuery(Integer tabType, LambdaQueryWrapper<PmsProductSpu> query) {
// 出售中商品
        if (ObjectUtil.equals(ProductSpuPageReqBO.FOR_SALE, tabType)) {
            query.eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.ENABLE.getStatus());
        }
        // 仓储中商品
        if (ObjectUtil.equals(ProductSpuPageReqBO.IN_WAREHOUSE, tabType)) {
            query.eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.DISABLE.getStatus());
        }
        // 已售空商品
        if (ObjectUtil.equals(ProductSpuPageReqBO.SOLD_OUT, tabType)) {
            query.eq(PmsProductSpu::getStock, 0)
                .eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.ENABLE.getStatus())
            ;
        }
        // 警戒库存
        if (ObjectUtil.equals(ProductSpuPageReqBO.ALERT_STOCK, tabType)) {
            query
                .gt(PmsProductSpu::getStock, 0)
                .le(PmsProductSpu::getStock, ProductConstants.ALERT_STOCK)
                // 如果库存触发警戒库存且状态为回收站的话则不在警戒库存列表展示
                .notIn(PmsProductSpu::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus());
        }
        // 回收站
        if (ObjectUtil.equals(ProductSpuPageReqBO.RECYCLE_BIN, tabType)) {
            query.eq(PmsProductSpu::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus());
        }
    }

    @Override
    public void updateBatchSpuStatus(ProductSpuBatchUpdateStatusReqBO updateReqVO) {
        for (Long id : updateReqVO.getIds()) {
            validateSpuExists(id);
        }
        // 更新状态
        LambdaUpdateWrapper<PmsProductSpu> lqw = Wrappers.lambdaUpdate();
        lqw.set(PmsProductSpu::getStatus, updateReqVO.getStatus()).in(PmsProductSpu::getId, updateReqVO.getIds());
        baseMapper.update(null, lqw);
    }

    @Override
    public List<PmsProductSpuVo> validateSpuList(Set<Long> spuIds) {
        if (CollUtil.isEmpty(spuIds)) {
            return Collections.emptyList();
        }
        // 获得商品信息
        List<PmsProductSpuVo> pmsProductSpuList = baseMapper.selectVoByIds(spuIds);
        Map<Long, PmsProductSpuVo> spuMap = CollectionUtils.convertMap(pmsProductSpuList, PmsProductSpuVo::getId);
        // 校验
        spuIds.forEach(id -> {
            PmsProductSpuVo spu = spuMap.get(id);
            if (spu == null) {
                throw new ServiceException(PmsErrorCodeConstants.SPU_NOT_EXISTS);
            }
            if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
                throw new ServiceException(PmsErrorCodeConstants.SPU_NOT_ENABLE, spu.getName());
            }
        });
        return pmsProductSpuList;
    }


    private void validateSpuExists(Long id) {
        if (baseMapper.selectById(id) == null) {
            throw new ServiceException(PmsErrorCodeConstants.SPU_NOT_EXISTS);
        }
    }

    /**
     * 基于 SKU 的信息，初始化 SPU 的信息
     * 主要是计数相关的字段，例如说市场价、最大最小价、库存等等
     *
     * @param spu  商品 SPU
     * @param skus 商品 SKU 数组
     */
    private void initSpuFromSkus(PmsProductSpu spu, List<ProductSkuSaveReqBO> skus) {
        // sku 单价最低的商品的价格
        spu.setPrice(CollectionUtils.getMinValue(skus, ProductSkuSaveReqBO::getPrice));
        // sku 单价最低的商品的市场价格
        spu.setMarketPrice(CollectionUtils.getMinValue(skus, ProductSkuSaveReqBO::getMarketPrice));
        // sku 单价最低的商品的成本价格
        spu.setCostPrice(CollectionUtils.getMinValue(skus, ProductSkuSaveReqBO::getCostPrice));
        // skus 库存总数
        spu.setStock(CollectionUtils.getSumValue(skus, ProductSkuSaveReqBO::getStock, Integer::sum));
        // sku 积分
        spu.setPoint(CollectionUtils.getMinValue(skus, ProductSkuSaveReqBO::getPoint));
        // 若是 spu 已有状态则不处理
        if (spu.getStatus() == null) {
            spu.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); // 默认状态为上架
            spu.setSalesCount(0); // 默认商品销量
            spu.setBrowseCount(0); // 默认商品浏览量
        }
    }

    private void validateCategory(Long categoryId) {
        categoryService.validateCategory(categoryId);
        // 校验层级
        if (categoryService.getCategoryLevel(categoryId) < ProductConstants.CATEGORY_LEVEL) {
            throw new ServiceException(PmsErrorCodeConstants.SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR);
        }
    }
}
